package net.zjitc.yaobei_backed.service.impl;

import net.zjitc.yaobei_backed.service.SmsService;
import net.zjitc.yaobei_backed.service.sms.SmsProvider;
import net.zjitc.yaobei_backed.service.sms.SmsProviderFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
 * 短信服务实现
 * 优先使用Redis，如果Redis不可用则使用内存存储
 * 支持真实短信发送，失败时自动降级到控制台打印
 */
@Service
public class SmsServiceImpl implements SmsService {

    private StringRedisTemplate redisTemplate;
    
    @Autowired
    private SmsProviderFactory smsProviderFactory;
    
    // 内存存储（当Redis不可用时使用）
    private final Map<String, CodeInfo> memoryStore = new ConcurrentHashMap<>();
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private boolean useMemoryStore = false;

    @Autowired(required = false)
    public void setRedisTemplate(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public String sendVerificationCode(String phone) {
        // 生成6位随机验证码
        String code = String.format("%06d", new Random().nextInt(999999));
        String key = "sms:code:" + phone;
        
        // 尝试使用Redis存储
        if (redisTemplate != null && !useMemoryStore) {
            try {
                redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
                System.out.println("=== 验证码已存储到Redis ===");
            } catch (Exception e) {
                // Redis连接失败，切换到内存存储
                System.out.println("=== Redis连接失败，切换到内存存储 ===");
                useMemoryStore = true;
            }
        }
        
        // 如果Redis不可用，使用内存存储
        if (useMemoryStore || redisTemplate == null) {
            memoryStore.put(key, new CodeInfo(code, System.currentTimeMillis() + 5 * 60 * 1000));
            // 5分钟后自动清理
            scheduler.schedule(() -> memoryStore.remove(key), 5, TimeUnit.MINUTES);
            System.out.println("=== 验证码已存储到内存 ===");
        }
        
        // 发送真实短信
        SmsProvider provider = smsProviderFactory.getProvider();
        try {
            boolean success = provider.sendVerificationCode(phone, code);
            if (success) {
                System.out.println("=== 验证码已通过" + provider.getProviderName() + "发送 ===");
            }
        } catch (Exception e) {
            // 发送失败时，降级到控制台打印（开发模式）
            System.err.println("=== 短信发送失败，降级到控制台打印 ===");
            System.err.println("错误信息: " + e.getMessage());
            System.out.println("=== 验证码发送（降级模式） ===");
            System.out.println("手机号: " + phone);
            System.out.println("验证码: " + code);
            System.out.println("========================");
        }
        
        // 开发阶段返回验证码，方便测试（生产环境应注释掉）
        return code;
    }

    @Override
    public boolean verifyCode(String phone, String code) {
        String key = "sms:code:" + phone;
        
        // 尝试从Redis读取
        if (redisTemplate != null && !useMemoryStore) {
            try {
                String storedCode = redisTemplate.opsForValue().get(key);
                if (storedCode != null) {
                    boolean isValid = storedCode.equals(code);
                    if (isValid) {
                        redisTemplate.delete(key);
                    }
                    return isValid;
                }
            } catch (Exception e) {
                // Redis连接失败，切换到内存存储
                useMemoryStore = true;
            }
        }
        
        // 从内存存储读取
        CodeInfo codeInfo = memoryStore.get(key);
        if (codeInfo == null) {
            return false;
        }
        
        // 检查是否过期
        if (System.currentTimeMillis() > codeInfo.expireTime) {
            memoryStore.remove(key);
            return false;
        }
        
        // 验证验证码
        boolean isValid = codeInfo.code.equals(code);
        if (isValid) {
            memoryStore.remove(key);
        }
        
        return isValid;
    }
    
    // 内部类：存储验证码和过期时间
    private static class CodeInfo {
        String code;
        long expireTime;
        
        CodeInfo(String code, long expireTime) {
            this.code = code;
            this.expireTime = expireTime;
        }
    }
}

